package com.emmy.likeview;

import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class LikeImageView extends View {

    //操作前点赞数量
    private int likeNumber = 9999999;

    private Bitmap unlikeBitmap;
    private Bitmap likeBitmap;
    private Bitmap shinkingBitmap;

    //textPaint用来绘制公共部分
    private Paint textPaint;
    //newTextPaint用来绘制变化的新部分
    private Paint newTextPaint;
    //oldTextPaint用来绘制变化的老部分
    private Paint oldTextPaint;
    private Paint bitmapPaint = new Paint();
    private Paint shinkingPaint = new Paint();
    private Paint circlePaint = new Paint();

    private int newWidth = 35;
    private int newHeight = 35;

    private int newShinkingWidth = 28;
    private int newShinkingHeight = 28;

    private int bitmapWidth;
    private int bitmapHeight;
    private int shinkingWidth;
    private int shinkingHeight;

    private float scaleWidth;
    private float scaleHeight;

    private float circleRadius = 0;
    private int circleAlpha = 0;

    private Paint.FontMetrics fontMetrics;
    //文字垂直居中需要的y偏移量
    private float offSet;
    //文字的Rect
    private Rect textRect;

    //变化前文字的alpha
    private int oldTextAlpha;
    //变化后文字的alpha
    private int newTextAlpha;
    //文字的宽度信息
    private float[] widths;

    //文字位置
    private float textX;
    private float textY;

    //新的文字Y轴位置
    private float newTextY;

    //旧的文字Y轴位置
    private float oldTextY;

    private Matrix matrix = new Matrix();
    private Matrix shinkingMatrix = new Matrix();

    //当前状态是否是点赞
    private boolean isLike = false;
    //是否是第一次加载绘制
    private boolean isFirst = true;

    public LikeImageView(Context context){
        this(context,null);
    }

    public LikeImageView(Context context, AttributeSet attributeSet){
       this(context, attributeSet,0);
    }

    public LikeImageView(Context context, AttributeSet attributeSet, int defStyleAttr){
        super(context, attributeSet, defStyleAttr);
        //获取xml文件配置属性
        TypedArray typedArray = context.obtainStyledAttributes(attributeSet, R.styleable.LikeImageView);
        likeNumber = typedArray.getInt(R.styleable.LikeImageView_likeNumber, 1999);
        init();
    }

    public void setLike(boolean like) {
        isLike = like;
    }

    public boolean getLike(){
        return isLike;
    }

    public int getLikeNumber() {
        return likeNumber;
    }

    public void setLikeNumber(int likeNumber) {
        this.likeNumber = likeNumber;
        invalidate();
    }

    public void setShinkAlpha(int alpha){
        shinkingPaint.setAlpha(alpha);
        invalidate();
    }

    public int getShinkAlpha(){
        return shinkingPaint.getAlpha();
    }

    public void setCircleRadius(float circleRadius){
        this.circleRadius = circleRadius;
        invalidate();
    }

    public float getCircleRadius() {
        return circleRadius;
    }

    public void setCircleAlpha(int circleAlpha){
        this.circleAlpha = circleAlpha;
        circlePaint.setAlpha(circleAlpha);
        invalidate();
    }

    public int getCircleAlpha(){
        return circleAlpha;
    }

    public void setNewTextAlpha(int newTextAlpha){
        this.newTextAlpha = newTextAlpha;
        newTextPaint.setAlpha(newTextAlpha);
        invalidate();
    }

    public int getNewTextAlpha(){
        return newTextAlpha;
    }

    public void setOldTextAlpha(int oldTextAlpha){
        this.oldTextAlpha = oldTextAlpha;
        oldTextPaint.setAlpha(oldTextAlpha);
        invalidate();
    }

    public int getOldTextAlpha(int oldTextAlpha){
        return oldTextAlpha;
    }

    public void setNewTextY(float newTextY){
        this.newTextY = newTextY;
        invalidate();
    }

    public float getNewTextY(){
        return newTextY;
    }

    public void setOldTextY(float oldTextY){
        this.oldTextY = oldTextY;
        invalidate();
    }

    public float getOldTextY(){
        return oldTextY;
    }

    private void init(){
        Resources resources = getResources();
        unlikeBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_message_unlike);
        likeBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_message_like);
        shinkingBitmap = BitmapFactory.decodeResource(resources, R.drawable.ic_message_like_shining);

        //初始化paint
        textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        textPaint.setTextSize(28);

        newTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        newTextPaint.setTextSize(28);

        oldTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        oldTextPaint.setTextSize(28);

        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setColor(Color.parseColor("#e4583e"));
        fontMetrics = textPaint.getFontMetrics();

        offSet = (fontMetrics.descent - fontMetrics.ascent)/2 - fontMetrics.descent;

        widths = new float[8];

        if (isLike)
            shinkingPaint.setAlpha(255);
        else
            shinkingPaint.setAlpha(0);

        bitmapWidth = unlikeBitmap.getWidth();
        bitmapHeight = unlikeBitmap.getHeight();

        shinkingWidth = shinkingBitmap.getWidth();
        shinkingHeight = shinkingBitmap.getHeight();

        scaleHeight = ((float)newHeight/bitmapHeight);
        scaleWidth = ((float)newWidth/bitmapWidth);

        matrix.postScale(scaleHeight, scaleWidth);
        shinkingMatrix.postScale(((float)newShinkingWidth/shinkingWidth),
                (float)newShinkingHeight/shinkingHeight);

        unlikeBitmap = Bitmap.createBitmap(unlikeBitmap,0,0,bitmapWidth,bitmapHeight,matrix,true);
        likeBitmap = Bitmap.createBitmap(likeBitmap,0,0,bitmapWidth,bitmapHeight,matrix,true);

        shinkingBitmap = Bitmap.createBitmap(shinkingBitmap,0,0,shinkingWidth,shinkingHeight,shinkingMatrix,true);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Bitmap bitmap = null;
        if (isLike) {
            bitmap = likeBitmap;
        }else{
            bitmap = unlikeBitmap;
        }
        //绘制小手
        canvas.drawBitmap(bitmap, SystemUtil.dp2px(getContext(),15),
                SystemUtil.dp2px(getContext(),10),bitmapPaint);
        //绘制四点
        canvas.drawBitmap(shinkingBitmap, SystemUtil.dp2px(getContext(),15),
                SystemUtil.dp2px(getContext(),5),shinkingPaint);
        textX = SystemUtil.dp2px(getContext(),30)+bitmap.getWidth();
        textY = bitmap.getHeight()+SystemUtil.dp2px(getContext(),10)-offSet;
        //绘制圆圈
        canvas.drawCircle(SystemUtil.dp2px(getContext(),15)+ bitmap.getWidth()/2,
                SystemUtil.dp2px(getContext(),10) + bitmap.getHeight()/2,
                circleRadius, circlePaint);
        //获取文字的长度
        String textValue = String.valueOf(likeNumber);
        int textLength = textValue.length();
        String oldTextValue;
        if (isFirst) {
            oldTextValue = textValue;
            isFirst = false;
        }else {
            if (isLike) {
                oldTextValue = String.valueOf(likeNumber - 1);
            } else {
                oldTextValue = String.valueOf(likeNumber + 1);
            }
        }
        //绘制文字，这种情况针对不同位数的变化，如99到100
        if (oldTextValue.length()!=textLength){
            canvas.drawText(oldTextValue,textX, oldTextY, oldTextPaint);
            canvas.drawText(textValue,textX, newTextY, newTextPaint);
            return;
        }
        /*
        下面这种情况区别与99/999/9999这种 就是相同位数变化
        把文字拆解成一个一个字符 就是获取字符串中每个字符的宽度，把结果填入参数widths
        相当于measureText()的一个快捷方法，计算等价于对字符串中的每个字符分别调用measureText()，并把
        它们的计算结果分别填入widths的不同元素*/
        textPaint.getTextWidths(textValue,widths);
        //将字符串转化为字符数组
        char[] chars = textValue.toCharArray();
        char[] oldchars = oldTextValue.toCharArray();
        float currentTextX = textX;
        for (int i = 0;i<chars.length;i++){
            if (chars[i]==oldchars[i]){
                //绘制相同部分
                textPaint.setAlpha(255);
                canvas.drawText(String.valueOf(chars[i]), currentTextX, textY, textPaint);
            }else{
                //绘制不同部分，具有动画
                canvas.drawText(String.valueOf(oldchars[i]),currentTextX, oldTextY, oldTextPaint);
                canvas.drawText(String.valueOf(chars[i]),currentTextX, newTextY, newTextPaint);
            }
            currentTextX += widths[i];
        }
    }

    /**
     * 测量宽高
     * 这两个参数是由父视图经过计算后传递给子视图
     * @param widthMeasureSpec 宽度
     * @param heightMeasureSpec 高度
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //MeasureSpec值由specMode和specSize共同组成，onMeasure两个参数的作用根据specMode的不同，有所区别。
        //当specMode为EXACTLY时，子视图的大小会根据specSize的大小来设置，对于布局参数中的match_parent或者精确大小值
        //当specMode为AT_MOST时，这两个参数只表示了子视图当前可以使用的最大空间大小，而子视图的实际大小不一定是specSize。所以我们自定义View时，重写onMeasure方法主要是在AT_MOST模式时，为子视图设置一个默认的大小，对于布局参数wrap_content。
        //高度默认是bitmap的高度加上下margin各10dp
        heightMeasureSpec = MeasureSpec.makeMeasureSpec(
                SystemUtil.dp2px(getContext(), 20+unlikeBitmap.getHeight())
                ,MeasureSpec.EXACTLY);
        //宽度默认是bitmap的宽度加左右margin各10dp和文字宽度和文字右侧10dp likeNumber是文本数字
        String textNum = String.valueOf(likeNumber);
        //得到文本的宽度
        float textWidth = textPaint.measureText(textNum, 0, textNum.length());
        //计算整个View的宽度 小手宽度 + 文本宽度 + 30px
        widthMeasureSpec = MeasureSpec.makeMeasureSpec(
                ((SystemUtil.dp2px(getContext(), 30+unlikeBitmap.getWidth() + textWidth))),
                MeasureSpec.EXACTLY
        );

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction()==MotionEvent.ACTION_DOWN){
            action();
        }
        return super.onTouchEvent(event);
    }

    private void action(){
        ObjectAnimator numberAnimator;
        ObjectAnimator shinkAlphaAnimator;
        ObjectAnimator circleRadiusAnimator;
        ObjectAnimator circleAlphaAnimator;
        ObjectAnimator oldTextAlphaAnimator;
        ObjectAnimator newTextAlphaAnimator;
        ObjectAnimator newTextYAnimator;
        ObjectAnimator oldTextYAnimator;
        AnimatorSet animatorSet = new AnimatorSet();
        if (isLike){
            newTextAlphaAnimator = ObjectAnimator.ofInt(this, "newTextAlpha", 0, 255);
            oldTextAlphaAnimator = ObjectAnimator.ofInt(this,"oldTextAlpha", 255, 0);
            newTextYAnimator = ObjectAnimator.ofFloat(this, "newTextY",
                    textY-SystemUtil.dp2px(getContext(), 10), textY);
            oldTextYAnimator = ObjectAnimator.ofFloat(this, "oldTextY",
                    textY, textY+SystemUtil.dp2px(getContext(), 10));
            numberAnimator = ObjectAnimator.ofInt(this, "likeNumber",--likeNumber);
            shinkAlphaAnimator = ObjectAnimator.ofInt(this, "shinkAlpha",255,0);
            animatorSet.playTogether(numberAnimator,shinkAlphaAnimator, newTextAlphaAnimator,
                    oldTextAlphaAnimator, newTextYAnimator, oldTextYAnimator);
            isLike = false;
        }else {
            newTextAlphaAnimator = ObjectAnimator.ofInt(this, "newTextAlpha", 0, 255);
            oldTextAlphaAnimator = ObjectAnimator.ofInt(this,"oldTextAlpha", 255, 0);
            newTextYAnimator = ObjectAnimator.ofFloat(this, "newTextY",
                    textY+SystemUtil.dp2px(getContext(), 10), textY);
            oldTextYAnimator = ObjectAnimator.ofFloat(this, "oldTextY",
                    textY, textY-SystemUtil.dp2px(getContext(), 10));
            numberAnimator = ObjectAnimator.ofInt(this, "likeNumber",++likeNumber);
            shinkAlphaAnimator = ObjectAnimator.ofInt(this, "shinkAlpha",0, 255);
            circleRadiusAnimator = ObjectAnimator.ofFloat(this, "circleRadius", 0,
                    likeBitmap.getHeight()/2 + SystemUtil.dp2px(getContext(),10));
            circleAlphaAnimator = ObjectAnimator.ofInt(this, "circleAlpha", 0, 255, 0);
            animatorSet.playTogether(numberAnimator,shinkAlphaAnimator, circleRadiusAnimator,
                    circleAlphaAnimator, newTextAlphaAnimator, oldTextAlphaAnimator,
                    newTextYAnimator, oldTextYAnimator);
            isLike = true;
        }
        animatorSet.start();
    }

    /**
     * 这个方法是在Activity resume的时候被调用，Activity对应的window被添加的时候
     * 每个view只会调用一次，可以做一些初始化操作
     * */
    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        unlikeBitmap.recycle();
        likeBitmap.recycle();
        shinkingBitmap.recycle();
    }

    private int compareStrs(String str1, String str2){
        int result = 0;
        if (str1.length()!=str2.length())
            throw new IllegalArgumentException("the length of two strings should be equal");
        for(int i=0;i<str1.length();i++){
            if (str1.charAt(i)==str2.charAt(i))
                result++;
            else
                return result;
        }
        return result;
    }
}
